<template>
  <div>
    <!--  list-type 是上传组件的类型 -->
    <!--  limit 是限制上传个数 -->
    <!--  action 是上传的地址  -->
    <!--  auto-upload 是否自动上传，默认为true -->
    <!-- file-list 上传文件的列表，一般用于回显图片内容  并不是双向绑定的！ 加 和 删 都不会自己改变 -->
    <!-- on-preview 钩子函数，是否可以预览，一旦配置就会出现加号 -->
    <!-- on-remove 钩子函数， 表示删除图标点击的时候会触发！ -->
    <!-- on-change 钩子函数， 添加文件、上传文件、上传失败时候 -->
    <!-- before-upload 钩子函数， 上传之前，如果返回false或者Promise的reject则挺着上传，true为可以上传 -->
    <!-- http-request 钩子函数， 自定义上传事件函数，赋给默认上传逻辑 -->
    <el-upload
      list-type="picture"
      action="#"
      :limit="limit"
      :file-list="fileList"
      :on-preview="onPreview"
      :on-remove="onRemove"
      :class="{ disabled:fileComputed }"
      :on-change="onChange"
      :before-upload="beforeUpload"
      :http-request="upload"
    >
        <el-button size="small" type="primary">点击上传</el-button>
    </el-upload>

    <!-- 预览弹框 -->
    <el-dialog
      title="图片"
      :visible.sync="showDialog"
      width="40%"
      append-to-body
    >
      <img style="width:100%" :src="imgUrl" alt="">
    </el-dialog>
  </div>
</template>
<script>
export default {
  name: 'ImageUpload',
  props: {
    // 最多个数
    limit: {
      type: Number,
      default: 1
    },
    // 文件最大数量
    maxSize: {
      type: Number,
      default: 5
    },
    // 文件字段
    fieldName: {
      type: String,
      required: true
    },
    // 上传处理函数
    uploadFn: {
      type: Function,
      required: true
    },
    // 预览地址
    value: {
      type: Array
    }
  },
  data () {
    return {
      // [{ name:'',url:'' },{}]
      fileList: [],
      showDialog: false, // 预览弹框打开
      imgUrl: '', // 预览图片地址
      currentFileUid: ''
    }
  },
  computed: {
    fileComputed () {
      return this.fileList.length === this.limit
    }
  },
  watch: {
    value: {
      handler () {
        // 是否有数据
        if (this.value.length) {
          this.fileList = this.value.map(val => ({
            url: process.env.VUE_APP_WEB_URL + val,
            upload: true,
            name: '点击查看详情'
          }))
        } else {
          this.fileList = []
        }
      },
      immediate: true
    }
  },
  methods: {
    // 图片预览事件
    onPreview (file) {
      this.imgUrl = file.url
      this.showDialog = true
    },
    // 图片删除事件
    onRemove (file, fileList) {
      // console.log(file)  // 删除的那个元素
      // console.log(fileList)  // 删除后的 fileList
      // 推荐手动去删除 this.fileList 里面的内容，而不是将fileList直接赋给 this.fileList
      this.fileList = this.fileList.filter(item => item.uid !== file.uid)
      // 外面更新
      this.updateOut()
    },
    // 文件发送变化的时候
    onChange (file, fileList) {
      // console.log(file)  // file.url  还是一个用JS生成的blob预览地址
      // console.log(fileList)   // 最新的文件列表
      // 需要等到上传成功、上传失败、选择文件的时候
      this.fileList = fileList.map(item => item)
    },
    // 上传之前的钩子
    beforeUpload (file) {
      // 类型校验
      const types = ['image/jpeg', 'image/gif', 'image/bmp', 'image/png', 'image/x-icon']
      if (!types.includes(file.type)) {
        this.$message.warning('上传图片只能是 JPG、GIF、BMP、PNG 格式!')
        return false
      }
      // 大小校验
      const maxSize = this.maxSize * 1024 * 1024
      if (file.size > maxSize) {
        this.$message.warning(`上传图片不能超过${this.maxSize}M`)
        return false
      }
      //   已经确定当前上传的就是当前的这个file了
      this.currentFileUid = file.uid // 【新增】
      // 通过
      return true
    },
    // 上传事件
    async upload ({ file }) {
      // console.log(file)  // 需要上传的文件信息
      // 我们需要在这里自己执行上传事件逻辑！找到上传接口，提交文件给上传接口完成上传
      if (file) {
        // 处理数据
        const data = new FormData()
        data.append(this.fieldName, file)
        // 提交后端
        const res = await this.uploadFn(data)
        // 将真实的地址去fileList里面替换本地生成的预览地址
        this.fileList = this.fileList.map(item => {
          if (item.uid === this.currentFileUid) {
            return { url: process.env.VUE_APP_WEB_URL + res.savePath, name: res.name, upload: true }
          }
          return item
        })
        // 外面更新
        this.updateOut()
      }
    },
    // 通知外面变化
    updateOut () {
      // 传递给外面
      let result = ''
      if (Array.isArray(this.value)) {
        result = this.fileList.filter(item => item.upload).map(val => val.url.replaceAll(process.env.VUE_APP_WEB_URL, ''))
      } else {
        result = this.fileList[0] ? this.fileList[0].url.replaceAll(process.env.VUE_APP_WEB_URL, '') : ''
      }
      this.$emit('input', result)
    }
  }
}
</script>
<style  lang='scss' scoped>
// 一旦 style加了 scoped 属性，就无法直接穿透修改组件内部的样式，需要使用deep
// 但是  scss 不支持  /deep/   需要使用 ::v-deep
::v-deep .disabled .el-upload--picture{
  display: none;
}
</style>
